#include "CRoleMgr.h"
#include "commclass.h"
#include "commmsg.h"
#include "commerrno.h"
#include "../mainctrl.h"
#include "../equip/CUserEquip.h"
#include "../equip/CEquipMgr.h"
#include "../data/CPlayerOnlineData.h"
#include "../soul/CSoulMgr.h"
#include "MsgGM.pb.h"
#include "MsgComm.pb.h"
#include "MsgMapInfo.pb.h"
#include "../notify/CNotifyMgr.h"
#include "MsgPet.pb.h"
#include "../simpleconfig/CRoleInitCfg.h"
#include "../simpleconfig/CRoleAttrCfg.h"
#include "../cmd/cmdupdatedata.h"

unsigned int CRoleMgr::GetNewGID()
{
    CZoneData & stZoneData = CMainCtrl::m_pstMain->m_stZoneOnlineData._stZoneData;
    int iNowGID = stZoneData._iNowGID;
    while(1)
    {
        int iIndex = CMainCtrl::m_pstMain->m_stPlayerSnsCommInfoHash.HashFind(stZoneData._uiZoneID * MAX_USER_PER_ZONE + iNowGID);
        if (iIndex >= 0)
        {
            ++iNowGID;
            if (iNowGID >= MAX_USER_PER_ZONE)   //ID取值范围 [1， MAX_USER_PER_ZONE - 1)
            {
                iNowGID = 1;
            }
        }
        else
        {
            break;
        }
    }

    stZoneData._iNowGID = (iNowGID + 1);  //保存未分配的起始家族ID
    CVarObjectKey stKey;
    stKey.m_chDataType = DT_ZONE_DATA;
    stKey.m_u64ID = stZoneData._uiZoneID;
    CMainCtrl::m_pstMain->UpdateData(stKey, stZoneData, VOP_UPDATE);

    return (unsigned int)(stZoneData._uiZoneID * MAX_USER_PER_ZONE + iNowGID);
}

int CRoleMgr::GetRoleFighting(CPlayerOnlineData& stPlayerOnline)
{
    return stPlayerOnline._iRoleFighting;
}

int CRoleMgr::GetTeamFighting(CPlayerOnlineData& stPlayerOnline)
{
    int iMountFighting = GetMountFighting(stPlayerOnline._uiNowMount,
            stPlayerOnline._usNowMountSkillLevel);

    return (stPlayerOnline._iRoleFighting + stPlayerOnline._iTeamFighting +
        iMountFighting);
}

int CRoleMgr::GetMountFighting(unsigned int uiMountID, int iSkillLevel)
{
    //坐骑战力
    int iMountFighting = 0;
    int iPara = 0;
    if (uiMountID > 0 && iSkillLevel > 0)
    {
        CMountCfgUnit stCfgData;
        CMainCtrl::m_pstMain->m_stMountMgr.GetConfig((unsigned short)uiMountID,
            stCfgData);
        switch (stCfgData._ucColor)
        {
        case MOUNT_COLOR_GREEN:
            {
                iPara = 100;
            }
            break;
        case MOUNT_COLOR_BLUE:
            {
                iPara = 150;
            }
            break;
        case MOUNT_COLOR_PURPLE:
            {
                iPara = 200;
            }
            break;
        case MOUNT_COLOR_GOLD:
            {
                iPara = 300;
            }
            break;
        default:
            break;
        }

        int64 i64Value = INT64_1 * iSkillLevel * iPara * 50;
        i64Value /= 100;
        iMountFighting = (int)i64Value;
    }

    return iMountFighting;
}

int CRoleMgr::RoleChkEquipStat(CPlayerDetailInfo& stPlayerDetail, unsigned int uiEquipID, int iPos)
{
    unsigned int uiOldEquipID;
    int iRet = stPlayerDetail._stPlayerEquip.GetEquip(uiOldEquipID, iPos);
    CT_RETURN(iRet);

    if (uiOldEquipID != uiEquipID)
    {
        if (0 == uiEquipID)
        {
            return ERROR_EQUIP_POS_NOT_CLEAR;
        }
        else
        {
            return ERROR_EQUIP_ID_NOT_MATCH;
        }
    }

    return 0;
}

int CRoleMgr::ReCalcRoleExtAttr(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfoEx1& stPlayerDetailEx1, bool bSendTeamFighting)
{
    //这里作为计算的起点

    int iRet = 0;
    CPlayerAttr & stPlayerAttr = stPlayerOnline._stUserRole.GetAttr();
    stPlayerAttr.Clear();

    //角色初始化配表的基础属性
    iRet = GetRoleInitBaseAttr(stPlayerAttr, stPlayerBase._ucCareer);
    CT_RETURN(iRet);

    //角色升级获得的基础属性
    iRet = CalcCareerLevelAttr(stPlayerAttr, stPlayerBase._ucCareer,
        stPlayerBase._shLevel, false);
    CT_RETURN(iRet);

    //角色默认的反击率
    if (stPlayerAttr.GetAttr(EXT_ATTR_FIGHT_BACK) < ATTR_ROLE_DEFAULT_FIGHT_BACK)
    {
        iRet = stPlayerAttr.AddAttr(EXT_ATTR_FIGHT_BACK, ATTR_ROLE_DEFAULT_FIGHT_BACK);
        CT_RETURN(iRet);
    }

    //装备提升的二级属性
    iRet = CMainCtrl::m_pstMain->m_stEquipMgr.GetEquipAttr(stPlayerOnline._stUserEquip, 0, stPlayerAttr);
    if (iRet){CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}

    //魂器属性
    CPlayerAttr stSoulAttr;
    iRet = CMainCtrl::m_pstMain->m_stSoulMgr.GetSoulAttr(stPlayerDetail._stSoulData, stSoulAttr);
    if (iRet){CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}

    stPlayerAttr += stSoulAttr;

    //家族技能的二级属性
    iRet = CMainCtrl::m_pstMain->m_stClanMgr.GetSkillAttr(stPlayerDetail._stUserClan, stPlayerAttr);
    if (iRet){CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}

    //魔药的属性
    iRet = CMainCtrl::m_pstMain->m_stDrugMgr.GetDrugAttr (stPlayerDetail, 0, stPlayerAttr);
    if (iRet){CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}

    //上课属性
    CPlayerAttr stLessonAttr;
    CMainCtrl::m_pstMain->m_stLessonMgr.GetAttr(stPlayerDetail._stUserLessonData, stLessonAttr);
    stPlayerAttr += stLessonAttr;

    //卡片属性
    CPlayerAttr stCardAttr;
    iRet = CMainCtrl::m_pstMain->m_stCardMgr.GetCardAttr(stPlayerOnline._stUserCard, 0, stPlayerDetail, stCardAttr);
    if (iRet){CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}
    stPlayerAttr += stCardAttr;

    //装备的套装属性
    CPlayerAttr stSuiteAttr;
    iRet = CMainCtrl::m_pstMain->m_stEquipMgr.GetSuiteAttr(stPlayerOnline._stUserEquip, 0, stSuiteAttr);
    if (iRet){CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}
    stPlayerAttr += stSuiteAttr;

    //秘宝二级属性
    iRet = CMainCtrl::m_pstMain->m_stTreasureMgr.CalcTreasureAttr(stPlayerDetail,
        stPlayerAttr, GAME_OBJ_TYPE_PLAYER, stPlayerDetail._uiGID);
    if (iRet){CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}

    //宠物属性
    if (stPlayerOnline._stUserPet.PetIsActive())
    {
        CPlayerAttr stPetAttr;
        iRet = CMainCtrl::m_pstMain->m_stPetMgr.GetPetAttr(stPlayerOnline._stUserPet, stPetAttr);
        if (iRet){CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}
        stPlayerAttr += stPetAttr;
    }

    //坐骑属性
    CPlayerAttr stMountAttr;
    int iMatrixPos = CMainCtrl::m_pstMain->m_stMatrixMgr.GetMatrixRtoLPos(
            stPlayerBase, stPlayerDetail, GAME_OBJ_TYPE_PLAYER,
            stPlayerBase._uiGID);
    if (iMatrixPos > 0)
    {
        iRet = CMainCtrl::m_pstMain->m_stMountMgr.GetMountAttr(
            stPlayerDetailEx1._stMount, iMatrixPos, stMountAttr);
        if (iRet){CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}
        stPlayerAttr += stMountAttr;
#ifdef _DEBUG
        CT_BATTLE(("主角(%u)阵位(%d)坐骑属性加成:",stPlayerBase._uiGID,
            iMatrixPos));
        DumpOnlineRoleInfo(stMountAttr);
#endif
    }

    //时装属性
    CPlayerAttr stFashionAttr;
    iRet = CMainCtrl::m_pstMain->m_stFashionMgr.GetFashionAttr(
        stPlayerDetailEx1._stUserFasion, stFashionAttr);
    if (iRet) {CT_ERROR(("时装属性%d, %d", iRet, stPlayerBase._uiGID));}
    stPlayerAttr += stFashionAttr;
#ifdef _DEBUG
        CT_BATTLE(("主角(%u)时装属性加成:",stPlayerBase._uiGID));
        DumpOnlineRoleInfo(stFashionAttr);
#endif

    //魔晶修正基础属性.
    iRet = CMainCtrl::m_pstMain->m_stEquipMgr.GetCrystalAttr(
        stPlayerOnline._stUserEquip, 0, true, stPlayerAttr);
    if (iRet){CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}

    //这个是基础属性换算为二级属性 需要放在计算战斗力之前
    iRet = CalcCareerBaseToExtAttr(stPlayerAttr, stPlayerBase._ucCareer);
    if (iRet){CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}

#if 0
    //魔晶修正二级属性. ( !!! 注意: 魔晶会对属性按百分比进行修正, "新增系统" 请跟策划确认属性修正的计算公式)
    iRet = CMainCtrl::m_pstMain->m_stEquipMgr.GetCrystalAttr(stPlayerOnline._stUserEquip, 0, false, stPlayerAttr);
    if (iRet){CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}

    int CMatrixMgr::GetMatrixPos(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, char chObjType, unsigned int uiID)
#endif
        //不被魔晶修正的二级属性 (请添加在下面).
        //角色先手值受装备强化等级卡片等级的修正
    iRet = AddObjTurnOrder(stPlayerAttr, GAME_OBJ_TYPE_PLAYER, 0, stPlayerDetail, stPlayerOnline);
    if (iRet){CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}

    //魔晶潜能
    CPlayerAttr stPotenAttr;
    iRet = CMainCtrl::m_pstMain->m_stEquipMgr.GetPotenAttr(stPlayerOnline._stUserEquip, stPlayerBase._ucCrystalPotenLevel, 0, stPotenAttr);
    if (iRet) {CT_ERROR(("%u %d", stPlayerBase._uiGID,iRet));}
    stPlayerAttr += stPotenAttr;

    //不被魔晶修正的二级属性 (请添加在上面).

    if (stPlayerOnline._bIsInitFinish)
    {
        //重新计算主角战斗力
        CalcObjFighting(stPlayerDetail._uiGID, GAME_OBJ_TYPE_PLAYER, 0);

        //重新计算团队战斗力
        CMainCtrl::m_pstMain->m_stMatrixMgr.CalcMainFighting(stPlayerDetail, stPlayerOnline);

        //下发用户属性
        CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stPlayerBase._uiGID, NOTIFY_ROLE_INFO);

        //下发团队战斗力变化给前端
        if (bSendTeamFighting)
        {
            CMainCtrl::m_pstMain->m_stMatrixMgr.SendMatrixFightingToFront(
                stPlayerBase, stPlayerDetail, stPlayerOnline);
        }
    }

    return 0;
}

int CRoleMgr::RoleWearEquip(CPlayerBaseInfo& stPlayerBase, CPlayerDetailInfo& stPlayerDetail,
                            CPlayerOnlineData& stPlayerOnline, unsigned int uiEquipID, int iPos)
{
    if (uiEquipID == 0)
    {
        return ERROR_EQUIP_UNKNOW_ID;
    }

    int iRet = 0;
    iRet = RoleChkEquipStat(stPlayerDetail, 0, iPos);
    CT_RETURN(iRet);

    iRet = stPlayerDetail._stPlayerEquip.SetEquip(uiEquipID, iPos);
    CT_RETURN(iRet);

    CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stPlayerBase._uiGID, NOTIFY_ROLE_ATTR);

    CMainCtrl::m_pstMain->m_stEquipMgr.NotifyEquipInMap (uiEquipID, stPlayerBase._uiGID);

    return 0;
}

int CRoleMgr::RoleTakeOffEquip(CPlayerBaseInfo& stPlayerBase, CPlayerDetailInfo& stPlayerDetail,
                               CPlayerOnlineData& stPlayerOnline, unsigned int uiEquipID, int iPos)
{
    if (uiEquipID == 0)
    {
        return ERROR_EQUIP_UNKNOW_ID;
    }

    int iRet = 0;
    iRet = RoleChkEquipStat(stPlayerDetail, uiEquipID, iPos);
    CT_RETURN(iRet);

    iRet = stPlayerDetail._stPlayerEquip.SetEquip(0, iPos);
    CT_RETURN(iRet);

    CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stPlayerBase._uiGID, NOTIFY_ROLE_ATTR);

    CMainCtrl::m_pstMain->m_stEquipMgr.NotifyEquipInMap (uiEquipID, stPlayerBase._uiGID);

    return 0;
}

int CRoleMgr::RoleAddExp(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, CPlayerOnlineData& stPlayerOnline,
        CPlayerDetailInfoEx1& stPlayerDetailEx1, int64 i64AddExp)
{
    short shOldLevel = stPlayerBase._shLevel;
    int iRet = stPlayerOnline._stUserRole.AddExp(stPlayerBase, stPlayerOnline,
            stPlayerDetailEx1, i64AddExp);
    CT_RETURN(iRet);

    if (stPlayerBase._shLevel > shOldLevel)
    {
        iRet = ReCalcRoleExtAttr(stPlayerBase, stPlayerDetail, stPlayerOnline,
            stPlayerDetailEx1, false);//在外部统一下发团队战斗力
        CT_RETURN(iRet);
    }

    return 0;
}

int CRoleMgr::GMDealRole(CPlayerBaseInfo& stPlayerBase, CPlayerDetailInfo& stPlayerDetail,
                         CPlayerOnlineData& stPlayerOnline, MsgReqGMPlayer& stReq, MsgAnsGMPlayer& stAns)
{
    int iRet = 0;
    int iAddExp = 0;
    unsigned int uiLevelExp = 0;
    switch (stReq.sub_type())
    {
    case ID_GM_PLAYER_SUB_ADD_LEVEL://修改角色等级
        if (stReq.datas_size() >= 1 && stReq.datas(0) > 0)
        {
            for (int i = stPlayerBase._shLevel; i < stReq.datas(0) && i < MAX_ROLE_LEVEL; ++i)
            {
                iRet = CMainCtrl::m_pstMain->m_stRoleConfigMgr.GetLevelUpExp((unsigned char)i, uiLevelExp);
                CT_RETURN(iRet);

                CDropItem stDropItem;
                stDropItem.DropRoleExp(uiLevelExp);
                stDropItem.SetOssModule(OSS_MODULE_GM);
                CMainCtrl::m_pstMain->m_stItemMgr.DropItem(NULL, stPlayerBase._uiGID, stDropItem);
            }
        }
        break;
    case ID_GM_PLAYER_SUB_ADD_EXP://修改角色经验
        if (stReq.datas_size() >= 1 && stReq.datas(0) > 0)
        {
            iAddExp += (int)stReq.datas(0);
        }
        else if (stReq.datas_size() >= 1 && stReq.datas(0) < 0)
        {
            stPlayerBase._i64NowExp += stReq.datas(0);
            if (stPlayerBase._i64NowExp < 0)
            {
                stPlayerBase._i64NowExp = 0;
            }
        }
        break;
    case ID_GM_PLAYER_SUB_ROLE_ATTR://查看角色属性
        {
            if (stReq.datas_size() >= 2)
            {
                int iType = stReq.datas(0);
                int iVal = stReq.datas(1);

                if (iType >= EXT_ATTR_MIM && iType <= EXT_ATTR_MAX && iVal >= 0)
                {
                    stPlayerOnline._stUserRole.GetAttr().SetAttr(iType, iVal);
                }
                else if (-1 == iType && iVal >= 0)
                {
                    for (int i = EXT_ATTR_MIM; i <= EXT_ATTR_MAX; ++i)
                    {
                        stPlayerOnline._stUserRole.GetAttr().SetAttr(i, iVal);
                    }
                }
            }

            GMCopyRoleAttr(stPlayerOnline._stUserRole.GetAttr(), stAns);
        }
        break;
    default:
        return ERROR_MAIN_SUB_CMD;
    }

    if (iAddExp > 0)
    {
        CDropItem stDropItem;
        stDropItem.DropRoleExp(iAddExp);
        stDropItem.SetOssModule(OSS_MODULE_GM);
        CMainCtrl::m_pstMain->m_stItemMgr.DropItem(NULL, stPlayerBase._uiGID, stDropItem);
    }

    return 0;
}

int CRoleMgr::GMCopyRoleAttr(CPlayerAttr& stPlayerAttr, MsgAnsGMPlayer& stAns)
{
    CTSizeString<1024> sAttrInfo;

    sAttrInfo.Cat("%s = %d\n", "智力", stPlayerAttr.GetAttr(BASE_ATTR_INT));
    sAttrInfo.Cat("%s = %d\n", "体力", stPlayerAttr.GetAttr(BASE_ATTR_VIT));
    sAttrInfo.Cat("%s = %d\n", "力量", stPlayerAttr.GetAttr(BASE_ATTR_STR));
    sAttrInfo.Cat("%s = %d\n", "敏捷", stPlayerAttr.GetAttr(BASE_ATTR_AGI));
    sAttrInfo.Cat("%s = %d\n", "生命", stPlayerAttr.GetAttr(EXT_ATTR_HP));
    sAttrInfo.Cat("%s = %d\n", "物攻", stPlayerAttr.GetAttr(EXT_ATTR_PHY_ATK));
    sAttrInfo.Cat("%s = %d\n", "物防", stPlayerAttr.GetAttr(EXT_ATTR_PHY_DEF));
    sAttrInfo.Cat("%s = %d\n", "魔攻", stPlayerAttr.GetAttr(EXT_ATTR_MAG_ATK));
    sAttrInfo.Cat("%s = %d\n", "魔防", stPlayerAttr.GetAttr(EXT_ATTR_MAG_DEF));
    sAttrInfo.Cat("%s = %d\n", "地攻", stPlayerAttr.GetAttr(EXT_ATTR_EARTH_ATK));
    sAttrInfo.Cat("%s = %d\n", "风攻", stPlayerAttr.GetAttr(EXT_ATTR_WIND_ATK));
    sAttrInfo.Cat("%s = %d\n", "火攻", stPlayerAttr.GetAttr(EXT_ATTR_FIRE_ATK));
    sAttrInfo.Cat("%s = %d\n", "水攻", stPlayerAttr.GetAttr(EXT_ATTR_WATER_ATK));
    sAttrInfo.Cat("%s = %d\n", "命中", stPlayerAttr.GetAttr(EXT_ATTR_HIT));
    sAttrInfo.Cat("%s = %d\n", "闪避", stPlayerAttr.GetAttr(EXT_ATTR_DODGE));
    sAttrInfo.Cat("%s = %d\n", "暴击", stPlayerAttr.GetAttr(EXT_ATTR_DOUBLE));
    sAttrInfo.Cat("%s = %d\n", "抗暴", stPlayerAttr.GetAttr(EXT_ATTR_ANTI_DOUBLE));
    sAttrInfo.Cat("%s = %d\n", "格挡", stPlayerAttr.GetAttr(EXT_ATTR_BLOCK));
    sAttrInfo.Cat("%s = %d\n", "破击", stPlayerAttr.GetAttr(EXT_ATTR_ANTI_BLOCK));
    sAttrInfo.Cat("%s = %d\n", "出手", stPlayerAttr.GetAttr(EXT_ATTR_TURN_ORDRE));
    sAttrInfo.Cat("%s = %d\n", "必杀", stPlayerAttr.GetAttr(EXT_ATTR_CRIT));
    sAttrInfo.Cat("%s = %d\n", "免伤", stPlayerAttr.GetAttr(EXT_ATTR_IMMUNE_INJURY));
    sAttrInfo.Cat("%s = %d\n", "反伤", stPlayerAttr.GetAttr(EXT_ATTR_REACT_INJURY));
    sAttrInfo.Cat("%s = %d\n", "穿透", stPlayerAttr.GetAttr(EXT_ATTR_PENETRATE));
    sAttrInfo.Cat("%s = %d\n", "痊愈", stPlayerAttr.GetAttr(EXT_ATTR_TREATMENT));
    sAttrInfo.Cat("%s = %d\n", "反击", stPlayerAttr.GetAttr(EXT_ATTR_FIGHT_BACK));
    sAttrInfo.Cat("%s = %d\n", "出场怒气", stPlayerAttr.GetAttr(EXT_ATTR_ACT_ANGER));

    stAns.set_name(sAttrInfo.Get());

    return 0;
}

int CRoleMgr::CopyRoleInfo(CPlayerBaseInfo& stPlayerBase, CPlayerDetailInfo& stPlayerDetail,
                           CPlayerOnlineData& stPlayerOnline, CPlayerSnsCommInfo& stPlayerSnsComm,
                           MsgRoleInfo& stMsgRoleInfo)
{
    int iRet = 0;

    stMsgRoleInfo.set_academy(stPlayerBase._ucAcademy);
    stMsgRoleInfo.set_rank(stPlayerSnsComm._iArenaRank);
    stMsgRoleInfo.set_name(stPlayerBase._sRoleName());
    stMsgRoleInfo.set_energy(
        stPlayerBase._stUserEnergy.GetEnergy(CMainCtrl::m_pstMain->m_iNow));
    stMsgRoleInfo.set_active_value(stPlayerBase._shActiveValue);
    stMsgRoleInfo.set_reputation(stPlayerDetail._iReputation);
    stMsgRoleInfo.set_team_fighting(GetTeamFighting(stPlayerOnline));
    stMsgRoleInfo.set_spirit_value(stPlayerDetail._stTreasureData._iSpirit);
    stMsgRoleInfo.set_hunli(stPlayerBase._iHunli);
    stMsgRoleInfo.set_lesson_point(
        stPlayerDetail._stUserLessonData._iLessonPoint);

    unsigned int uiLevelUpExp = 0;
    iRet = CMainCtrl::m_pstMain->m_stRoleConfigMgr.GetLevelUpExp(
        (unsigned char)stPlayerBase._shLevel, uiLevelUpExp);
    if (iRet != 0)
    {
        CT_WARNING(("get level up exp error, level %d", stPlayerBase._shLevel));
    }

    MsgObjBase* pstObjBase = stMsgRoleInfo.mutable_base_info();
    pstObjBase->set_sex(stPlayerBase._ucIsMale);
    pstObjBase->set_career(stPlayerBase._ucCareer);
    pstObjBase->set_level(stPlayerBase._shLevel);
    pstObjBase->set_level_up_exp((int)uiLevelUpExp);
    pstObjBase->set_now_exp((int)(stPlayerBase._i64NowExp & 0x7FFFFFFF));
    pstObjBase->set_obj_fighting(GetRoleFighting(stPlayerOnline));

    CopyBaseAttr(stPlayerOnline._stUserRole.GetAttr(),
        *(pstObjBase->mutable_attrs()));

    CopyExtAttr(stPlayerOnline._stUserRole.GetAttr(),
        *(pstObjBase->mutable_fight_attrs()));

#if 0
    //拷贝技能信息给前端 由前端判断技能系统开关来决定是否显示技能
    if (CMainCtrl::m_pstMain->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_37,
        stPlayerBase, stPlayerOnline))
    {
        MsgObjSkill* pstMsgObjSkill = pstObjBase->mutable_skill_info();
        pstMsgObjSkill->set_activate_skill(
            stPlayerOnline._stUserRole.GetMagicSkillID());
        CMainCtrl::m_pstMain->m_stSoulMgr.GetSoulSkillList(stPlayerBase,
            stPlayerDetail, *(pstMsgObjSkill->mutable_skill_list()));
    }
#else
    MsgObjSkill* pstMsgObjSkill = pstObjBase->mutable_skill_info();
    pstMsgObjSkill->set_activate_skill(
        stPlayerOnline._stUserRole.GetMagicSkillID());
    CMainCtrl::m_pstMain->m_stSoulMgr.GetSoulSkillList(stPlayerBase,
        stPlayerDetail, *(pstMsgObjSkill->mutable_skill_list()));
#endif

    //秘宝 只返回个体身上携带的秘宝单元
    CMainCtrl::m_pstMain->m_stTreasureMgr.GetObjBaseTreasure(stPlayerDetail,
        *(pstObjBase), GAME_OBJ_TYPE_PLAYER, stPlayerDetail._uiGID);

    //宠物简略信息
    stMsgRoleInfo.clear_pet_info();
    MsgPetBriefInfo* pstPetBriefInfo = stMsgRoleInfo.mutable_pet_info();
    stPlayerOnline._stUserPet.GetPetBriefInfo((*pstPetBriefInfo));

    MsgUserClan* pstUserclan = stMsgRoleInfo.mutable_clan();
    pstUserclan->set_clan_id(stPlayerSnsComm._uiClanId);
    pstUserclan->set_clan_contri(stPlayerSnsComm._iContribution);

    if (stPlayerSnsComm._uiClanId > 0)
    {
        CTSizeString<CLAN_NAME_STRING_SIZE> stClanName;
        CMainCtrl::m_pstMain->m_stClanMgr.GetClanName(stPlayerSnsComm._uiClanId,
            stClanName);
        pstUserclan->set_clan_name(stClanName());
        pstUserclan->set_clan_level(
            CMainCtrl::m_pstMain->m_stClanMgr.GetClanLevel(
                stPlayerSnsComm._uiClanId));
    }

    int iTitle;
    CMainCtrl::m_pstMain->m_stClanMgr.GetClanTitle(stPlayerBase._uiGID, iTitle);
    pstUserclan->set_title(iTitle);

    for (int i = 0; i < stPlayerSnsComm._stTitle._astTitles.Size(); i++)
    {
        CRoleTitle & stTitle = stPlayerSnsComm._stTitle._astTitles[i];
        if (stTitle._iExpiredTime > CMainCtrl::m_pstMain->m_iNow)
        {
            MsgRoleTitle * pstTitle = stMsgRoleInfo.add_titles();
            pstTitle->set_type(stTitle._ucTitle);
            pstTitle->set_expired_time(stTitle._iExpiredTime);
        }
    }

    stMsgRoleInfo.set_potential_level(stPlayerBase._ucCrystalPotenLevel);
    stMsgRoleInfo.set_potential_exp(stPlayerBase._iCrystalPotenExp);

    stMsgRoleInfo.set_bless_point(stPlayerDetail._stUserEquip._iBlessPoint);
    stMsgRoleInfo.set_mount_id(stPlayerOnline._uiNowMount);
    
    if (stPlayerOnline._uiNowWing > 0)
    {
        stMsgRoleInfo.set_wing_id(stPlayerOnline._uiNowWing);
        stMsgRoleInfo.set_wing_mode(stPlayerOnline._ucWingMode);
        stMsgRoleInfo.set_wing_end_time(stPlayerOnline._iWingEndTime);
    }

    if (stPlayerOnline._uiNowDress > 0)
    {
        stMsgRoleInfo.set_dress_id(stPlayerOnline._uiNowDress);
        stMsgRoleInfo.set_dress_mode(stPlayerOnline._ucDressMode);
        stMsgRoleInfo.set_dress_end_time(stPlayerOnline._iDressEndTime);
    }

    stMsgRoleInfo.set_fashion_master_level(stPlayerOnline._ucFashionLevel);

    return 0;
}

//拷贝个体基础属性
int CRoleMgr::CopyBaseAttr(CPlayerAttr& stPlayerAttr, MsgRoleBaseAttrs& stMsgBaseAttr)
{
    stMsgBaseAttr.set_wit(stPlayerAttr.GetAttr(BASE_ATTR_INT));
    stMsgBaseAttr.set_vit(stPlayerAttr.GetAttr(BASE_ATTR_VIT));
    stMsgBaseAttr.set_str(stPlayerAttr.GetAttr(BASE_ATTR_STR));
    stMsgBaseAttr.set_agi(stPlayerAttr.GetAttr(BASE_ATTR_AGI));

    return 0;
}

//拷贝个体二级属性
int CRoleMgr::CopyExtAttr(CPlayerAttr& stPlayerAttr, MsgRoleFightAttrs& stMsgExtAttr)
{
    stMsgExtAttr.set_max_hp(stPlayerAttr.GetAttr(EXT_ATTR_HP));						//生命
    stMsgExtAttr.set_max_courage(0);		//勇气 byronwei_tmp
    stMsgExtAttr.set_phy_atk(stPlayerAttr.GetAttr(EXT_ATTR_PHY_ATK));				//物攻
    stMsgExtAttr.set_phy_def(stPlayerAttr.GetAttr(EXT_ATTR_PHY_DEF));				//物防
    stMsgExtAttr.set_mag_atk(stPlayerAttr.GetAttr(EXT_ATTR_MAG_ATK));				//魔攻
    stMsgExtAttr.set_mag_def(stPlayerAttr.GetAttr(EXT_ATTR_MAG_DEF));				//魔防
    stMsgExtAttr.set_earth_atk(stPlayerAttr.GetAttr(EXT_ATTR_EARTH_ATK));			//地攻
    stMsgExtAttr.set_water_atk(stPlayerAttr.GetAttr(EXT_ATTR_WATER_ATK));			//水攻
    stMsgExtAttr.set_fire_atk(stPlayerAttr.GetAttr(EXT_ATTR_FIRE_ATK));				//火攻
    stMsgExtAttr.set_wind_atk(stPlayerAttr.GetAttr(EXT_ATTR_WIND_ATK));				//风攻
    stMsgExtAttr.set_hit_rate(stPlayerAttr.GetAttr(EXT_ATTR_HIT));					//命中
    stMsgExtAttr.set_dodge_rate(stPlayerAttr.GetAttr(EXT_ATTR_DODGE));				//闪避
    stMsgExtAttr.set_double_rate(stPlayerAttr.GetAttr(EXT_ATTR_DOUBLE));			//暴击
    stMsgExtAttr.set_anti_double_rate(stPlayerAttr.GetAttr(EXT_ATTR_ANTI_DOUBLE));	//抗暴
    stMsgExtAttr.set_crit_rate(stPlayerAttr.GetAttr(EXT_ATTR_CRIT));				//必杀
    stMsgExtAttr.set_block_rate(stPlayerAttr.GetAttr(EXT_ATTR_BLOCK));				//格档
    stMsgExtAttr.set_anti_block_rate(stPlayerAttr.GetAttr(EXT_ATTR_ANTI_BLOCK));	//破击
    stMsgExtAttr.set_turn_order_value(stPlayerAttr.GetAttr(EXT_ATTR_TURN_ORDRE));	//出手速度
    stMsgExtAttr.set_anger_recover_rate(0);//怒气恢复速度 byronwei_tmp
    stMsgExtAttr.set_courage_recover_rate(0);//勇气恢复速度 byronwei_tmp
    stMsgExtAttr.set_right_back_rate(stPlayerAttr.GetAttr(EXT_ATTR_FIGHT_BACK));	//反击
    stMsgExtAttr.set_immune_injury(stPlayerAttr.GetAttr(EXT_ATTR_IMMUNE_INJURY));   //免伤
    stMsgExtAttr.set_react_injury(stPlayerAttr.GetAttr(EXT_ATTR_REACT_INJURY));     //反伤
    stMsgExtAttr.set_penetrate_rate(stPlayerAttr.GetAttr(EXT_ATTR_PENETRATE));      //穿透
    stMsgExtAttr.set_treatment_rate(stPlayerAttr.GetAttr(EXT_ATTR_TREATMENT));      //痊愈
    stMsgExtAttr.set_act_anger(stPlayerAttr.GetAttr(EXT_ATTR_ACT_ANGER));//出场怒气

    return 0;
}

//单独由个体属性计算战斗力
int CRoleMgr::CalcFighting(CPlayerAttr& stPlayerAttr, int& iFighting)
{
    //除了人物属性影响战斗力外可能还有其他因素
    //除数由策划文档指定
    iFighting = stPlayerAttr.GetAttr(EXT_ATTR_HP) / 30 +            //生命
        (stPlayerAttr.GetAttr(EXT_ATTR_PHY_ATK) +           //物攻
        stPlayerAttr.GetAttr(EXT_ATTR_MAG_ATK)) / 15 +     //魔攻
        (stPlayerAttr.GetAttr(EXT_ATTR_PHY_DEF) +           //物防
        stPlayerAttr.GetAttr(EXT_ATTR_MAG_DEF)) / 5 +      //魔防
        stPlayerAttr.GetAttr(EXT_ATTR_HIT) +                //命中
        stPlayerAttr.GetAttr(EXT_ATTR_DODGE) +              //闪避
        stPlayerAttr.GetAttr(EXT_ATTR_DOUBLE) +             //暴击
        stPlayerAttr.GetAttr(EXT_ATTR_ANTI_DOUBLE) +        //抗暴
        stPlayerAttr.GetAttr(EXT_ATTR_ANTI_BLOCK) +         //破击
        stPlayerAttr.GetAttr(EXT_ATTR_BLOCK) +              //格挡
        stPlayerAttr.GetAttr(EXT_ATTR_CRIT) +               //必杀
        stPlayerAttr.GetAttr(EXT_ATTR_REACT_INJURY) +       //反伤
        stPlayerAttr.GetAttr(EXT_ATTR_PENETRATE) +          //穿透
        stPlayerAttr.GetAttr(EXT_ATTR_IMMUNE_INJURY) +      //免伤
        stPlayerAttr.GetAttr(EXT_ATTR_TREATMENT) +          //痊愈
        stPlayerAttr.GetAttr(EXT_ATTR_ACT_ANGER) * 10 +     //出场怒气
        (stPlayerAttr.GetAttr(EXT_ATTR_TURN_ORDRE) * 3 / 2);  //先攻值
    iFighting = iFighting * 2;
    return 0;
}

//使用已有的个体属性计算一个完整个体(主角或者伙伴)的战斗力
int CRoleMgr::CalcObjFighting(unsigned int uiGID, int iObjType, int iAuxData)
{
    if (GAME_OBJ_TYPE_PLAYER != iObjType && GAME_OBJ_TYPE_PARTNER != iObjType)
    {
        CT_ERROR(("unknow game obj type(%d) when calc fighting",iObjType));
        return 0;
    }

    //这里是计算的起点

    int iIndex = 0;
    int iAttrFighting = 0; //属性战斗力
    int iTreasureFighting = 0; //秘宝等级战斗力
    int iPetStarFighting = 0; //宠物星级战斗力
    int iPartnerLockFighting = 0; //伙伴锁链战斗力

    iIndex = CMainCtrl::m_pstMain->m_stPlayerDetailInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("no detail data user(%u) when calc fighting",uiGID));
        return 0;
    }

    CPlayerDetailInfo& stPlayerDetail =
        CMainCtrl::m_pstMain->m_stPlayerDetailInfoHash[iIndex];

    iIndex = CMainCtrl::m_pstMain->m_stPlayerOnlineDataHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("no online data user(%u) when calc fighting",uiGID));
        return 0;
    }

    CPlayerOnlineData& stPlayerOnline =
        CMainCtrl::m_pstMain->m_stPlayerOnlineDataHash[iIndex];

    if (GAME_OBJ_TYPE_PLAYER == iObjType)
    {
        CalcFighting(stPlayerOnline._stUserRole.GetAttr(), iAttrFighting);

        iTreasureFighting =
            CMainCtrl::m_pstMain->m_stTreasureMgr.GetTreasureFighting(
            stPlayerDetail, GAME_OBJ_TYPE_PLAYER, uiGID);

        stPlayerOnline._iRoleFighting =
            iAttrFighting + iTreasureFighting + iPetStarFighting;

        CT_TRACE(("Role(%u)ObjFighting(%d):AttrFighting(%d)+TreasureFighting" \
            "(%d)+PetStarFighting(%d)",
            uiGID,stPlayerOnline._iRoleFighting,iAttrFighting,
            iTreasureFighting,iPetStarFighting));
    }
    else if (GAME_OBJ_TYPE_PARTNER == iObjType)
    {
        short shPartnerID = (short)iAuxData;

        iIndex = stPlayerOnline._stUserPartner.FindPartner(shPartnerID);
        if (iIndex < 0)
        {
            CT_WARNING(("role(%u) calc partner(%d) fighting but obj no in act",
                uiGID,shPartnerID));
            return 0;
        }

        CPartnerUnit& stPartnerUnit =
            stPlayerOnline._stUserPartner.GetPartner(iIndex);

        CalcFighting(stPartnerUnit._stAttr, iAttrFighting);

        iIndex = stPlayerDetail._stUserPartner.FindActData(shPartnerID);
        if (iIndex < 0)
        {
            CT_WARNING(("role(%u) calc partner(%d) fighting but obj no in act",
                uiGID,shPartnerID));
            return 0;
        }

        CPartnerActData& stPartnerActData =
            stPlayerDetail._stUserPartner.GetPartnerActData(iIndex);
        if (stPartnerActData._iFavor >= PARTNER_FAVOR_FOR_POWER)
        {
            iPartnerLockFighting += PARTNER_POWER_ADD_FIGHTING;
        }

        iTreasureFighting =
            CMainCtrl::m_pstMain->m_stTreasureMgr.GetTreasureFighting(
            stPlayerDetail, GAME_OBJ_TYPE_PARTNER, shPartnerID);

        stPartnerUnit._iFighting =
            iAttrFighting + iTreasureFighting + iPetStarFighting +
            iPartnerLockFighting;

        CT_TRACE(("Role(%u)Partner(%d)ObjFighting(%d):AttrFighting(%d)+" \
            "TreasureFighting(%d)+PetStarFighting(%d)LockFighting(%d)",
            uiGID,shPartnerID,stPartnerUnit._iFighting,iAttrFighting,
            iTreasureFighting,iPetStarFighting,iPartnerLockFighting));
    }

    return 0;
}

void CRoleMgr::DumpOnlineRoleInfo(CPlayerAttr& stPlayerAttr)
{
    int iFighting = 0;
    CalcFighting(stPlayerAttr, iFighting);
    CT_BATTLE(("%-18s 提升战斗力为%d", "打印二级属性结构:", iFighting));
    CT_BATTLE(("%-18s = %d", "智力", stPlayerAttr.GetAttr(BASE_ATTR_INT)));
    CT_BATTLE(("%-18s = %d", "体力", stPlayerAttr.GetAttr(BASE_ATTR_VIT)));
    CT_BATTLE(("%-18s = %d", "力量", stPlayerAttr.GetAttr(BASE_ATTR_STR)));
    CT_BATTLE(("%-18s = %d", "敏捷", stPlayerAttr.GetAttr(BASE_ATTR_AGI)));
    CT_BATTLE(("%-18s = %d", "生命", stPlayerAttr.GetAttr(EXT_ATTR_HP)));
    CT_BATTLE(("%-18s = %d", "物攻", stPlayerAttr.GetAttr(EXT_ATTR_PHY_ATK)));
    CT_BATTLE(("%-18s = %d", "物防", stPlayerAttr.GetAttr(EXT_ATTR_PHY_DEF)));
    CT_BATTLE(("%-18s = %d", "魔攻", stPlayerAttr.GetAttr(EXT_ATTR_MAG_ATK)));
    CT_BATTLE(("%-18s = %d", "魔防", stPlayerAttr.GetAttr(EXT_ATTR_MAG_DEF)));
    CT_BATTLE(("%-18s = %d", "地攻", stPlayerAttr.GetAttr(EXT_ATTR_EARTH_ATK)));
    CT_BATTLE(("%-18s = %d", "风攻", stPlayerAttr.GetAttr(EXT_ATTR_WIND_ATK)));
    CT_BATTLE(("%-18s = %d", "火攻", stPlayerAttr.GetAttr(EXT_ATTR_FIRE_ATK)));
    CT_BATTLE(("%-18s = %d", "水攻", stPlayerAttr.GetAttr(EXT_ATTR_WATER_ATK)));
    CT_BATTLE(("%-18s = %d", "命中", stPlayerAttr.GetAttr(EXT_ATTR_HIT)));
    CT_BATTLE(("%-18s = %d", "闪避", stPlayerAttr.GetAttr(EXT_ATTR_DODGE)));
    CT_BATTLE(("%-18s = %d", "暴击", stPlayerAttr.GetAttr(EXT_ATTR_DOUBLE)));
    CT_BATTLE(("%-18s = %d", "抗暴", stPlayerAttr.GetAttr(EXT_ATTR_ANTI_DOUBLE)));
    CT_BATTLE(("%-18s = %d", "格挡", stPlayerAttr.GetAttr(EXT_ATTR_BLOCK)));
    CT_BATTLE(("%-18s = %d", "破击", stPlayerAttr.GetAttr(EXT_ATTR_ANTI_BLOCK)));
    CT_BATTLE(("%-18s = %d", "出手速度", stPlayerAttr.GetAttr(EXT_ATTR_TURN_ORDRE)));
    CT_BATTLE(("%-18s = %d", "必杀", stPlayerAttr.GetAttr(EXT_ATTR_CRIT)));
    CT_BATTLE(("%-18s = %d", "免伤", stPlayerAttr.GetAttr(EXT_ATTR_IMMUNE_INJURY)));
    CT_BATTLE(("%-18s = %d", "反伤", stPlayerAttr.GetAttr(EXT_ATTR_REACT_INJURY)));
    CT_BATTLE(("%-18s = %d", "穿透", stPlayerAttr.GetAttr(EXT_ATTR_PENETRATE)));
    CT_BATTLE(("%-18s = %d", "痊愈", stPlayerAttr.GetAttr(EXT_ATTR_TREATMENT)));
    CT_BATTLE(("%-18s = %d", "反击", stPlayerAttr.GetAttr(EXT_ATTR_FIGHT_BACK)));
    CT_BATTLE(("%-18s = %d", "出场怒气", stPlayerAttr.GetAttr(EXT_ATTR_ACT_ANGER)));
}

int CRoleMgr::GetRoleLevel(unsigned int uiGid, short & shRoleLevel)
{
    CMainCtrl * pstMain = CMainCtrl::m_pstMain;

    int iIndex =  pstMain->m_stPlayerSnsCommInfoHash.HashFind(uiGid);
    if (iIndex < 0)
    {
        return ERROR_LACK_SNS_INFO;
    }

    shRoleLevel = (short)pstMain->m_stPlayerSnsCommInfoHash[iIndex]._usLevel;
    return 0;
}

const char * CRoleMgr::GetRoleName (unsigned int uiGid)
{
    if (0 == uiGid)
    {
        return "";
    }

    CMainCtrl * pstMain = CMainCtrl::m_pstMain;

    int iIndex =  pstMain->m_stPlayerSnsCommInfoHash.HashFind(uiGid);
    if (iIndex < 0)
    {
        CT_ERROR(("%d", uiGid));
        return "";
    }

    return pstMain->m_stPlayerSnsCommInfoHash[iIndex]._sRoleName();
}

int CRoleMgr::CheckValidCareer(int iCareer)
{
    if (CAREER_1 == iCareer || CAREER_2 == iCareer ||
        CAREER_3 == iCareer || CAREER_4 == iCareer)
    {
        return 0;
    }

    return ERROR_ROLE_CAREER_INVALID;
}

int CRoleMgr::CheckValidBaseAttr(int iBaseType)
{
    if (BASE_ATTR_INT == iBaseType || BASE_ATTR_VIT == iBaseType ||
        BASE_ATTR_STR == iBaseType || BASE_ATTR_AGI == iBaseType)
    {
        return 0;
    }

    return ERROR_ROLE_BASE_ATTR_INVALID;
}

#define ROLE_CAREER_ATTR_BASE 10    //职业属性ID = (职业 * 10) + 基础属性类型

int CRoleMgr::CheckValidCareerAttr(int iID)
{
    int iRet = 0;
    int iCareer = 0;
    int iBaseType = 0;

    if (iID <= 0)
    {
        return ERROR_ROLE_CAREER_ATTR_ID_INVALID;
    }

    iCareer = iID / ROLE_CAREER_ATTR_BASE;
    iBaseType = iID % ROLE_CAREER_ATTR_BASE;

    iRet = CheckValidCareer(iCareer);
    CT_RETURN(iRet);

    iRet = CheckValidBaseAttr(iBaseType);
    CT_RETURN(iRet);

    return 0;
}

int CRoleMgr::GetCareerAttrID(int iCareer, int iBaseType, int& iID)
{
    int iRet = 0;

    iRet = CheckValidCareer(iCareer);
    CT_RETURN(iRet);

    iRet = CheckValidBaseAttr(iBaseType);
    CT_RETURN(iRet);

    iID = iCareer * ROLE_CAREER_ATTR_BASE + iBaseType;

    return 0;
}

int CRoleMgr::GetCareerBaseTypeByID(int& iCareer, int& iBaseType, int iID)
{
    int iRet = 0;

    iRet = CheckValidCareerAttr(iID);
    CT_RETURN(iRet);

    iCareer = iID / ROLE_CAREER_ATTR_BASE;
    iBaseType = iID % ROLE_CAREER_ATTR_BASE;

    return 0;
}

int CRoleMgr::GetRoleInitBaseAttr(CPlayerAttr& stPlayerAttr, int iCareer)
{
    int iRet = 0;
    int iIndex = 0;

    iRet = CheckValidCareer(iCareer);
    CT_RETURN(iRet);

    iIndex = CMainCtrl::m_pstMain->m_stRoleConfigMgr.FindRoleInitCfg(iCareer);
    CT_CHECK(iIndex, ERROR_ROLE_INIT_EMPTY_CFG);

    CRoleInitCfgData& stRoleInitCfg =
        CMainCtrl::m_pstMain->m_stRoleConfigMgr.GetRoleInitCfg(iIndex);

    stPlayerAttr += stRoleInitCfg._stInitAttr;

    stPlayerAttr._aiAttr[BASE_ATTR_INT] += stRoleInitCfg._iInt;
    stPlayerAttr._aiAttr[BASE_ATTR_VIT] += stRoleInitCfg._iVit;
    stPlayerAttr._aiAttr[BASE_ATTR_STR] += stRoleInitCfg._iStr;
    stPlayerAttr._aiAttr[BASE_ATTR_AGI] += stRoleInitCfg._iAgi;

    return 0;
}

int CRoleMgr::CalcCareerLevelAttr(CPlayerAttr& stPlayerAttr, int iCareer,
                                  int iLevel, bool bCalcExtAttr)
{
    int iID = 0;
    int iRet = 0;
    int iIndex = 0;
    int iBaseType = 0;
    int64 i64RatioTmp = 0;

    if (iLevel <= 0)//主角或者伙伴初始等级为1级
    {
        return ERROR_ROLE_CAREER_ATTR_LEVLE;
    }

    if (iLevel <= 0)
    {
        if (bCalcExtAttr)
        {
            iRet = CalcCareerBaseToExtAttr(stPlayerAttr, iCareer);
            CT_RETURN(iRet);
        }

        return 0;//不需要往下走
    }

    CTLib::CTArray<int, BASE_ATTR_MAX> aiBaseType;
    aiBaseType.m_iUsedCount = aiBaseType.GetCount();
    aiBaseType[0] = BASE_ATTR_INT;
    aiBaseType[1] = BASE_ATTR_VIT;
    aiBaseType[2] = BASE_ATTR_STR;
    aiBaseType[3] = BASE_ATTR_AGI;

    for (int i = 0; i < aiBaseType.Size(); ++i)
    {
        iBaseType = aiBaseType[i];

        iRet = GetCareerAttrID(iCareer, iBaseType, iID);
        CT_RETURN(iRet);

        iIndex = CMainCtrl::m_pstMain->m_stRoleConfigMgr.FindRoleAttrCfg(iID);
        CT_CHECK(iIndex, ERROR_ROLE_CAREER_ATTR_EMPTY_CFG);

        CRoleAttrCfgData& stAttrCfgData =
            CMainCtrl::m_pstMain->m_stRoleConfigMgr.GetRoleAttrCfg(iIndex);

        i64RatioTmp = INT64_1 * iLevel * stAttrCfgData.GetLevelUnit();
        i64RatioTmp /= BATTLE_RATE_SKILL_PERCENT;

        stPlayerAttr._aiAttr[iBaseType] += (int)(i64RatioTmp);
    }

    if (bCalcExtAttr)
    {
        iRet = CalcCareerBaseToExtAttr(stPlayerAttr, iCareer);
        CT_RETURN(iRet);
    }

    return 0;
}

int CRoleMgr::CalcCareerBaseToExtAttr(CPlayerAttr& stAttr, int iCareer)
{
    int iID = 0;
    int iRet = 0;
    int iIndex = 0;
    int iBaseType = 0;
    int iBaseAttr = 0;

    CTLib::CTArray<int, BASE_ATTR_MAX> aiBaseType;
    aiBaseType.m_iUsedCount = aiBaseType.GetCount();
    aiBaseType[0] = BASE_ATTR_INT;
    aiBaseType[1] = BASE_ATTR_VIT;
    aiBaseType[2] = BASE_ATTR_STR;
    aiBaseType[3] = BASE_ATTR_AGI;

    for (int i = 0; i < aiBaseType.Size(); ++i)
    {
        iBaseType = aiBaseType[i];

        iRet = GetCareerAttrID(iCareer, iBaseType, iID);
        CT_RETURN(iRet);

        iIndex = CMainCtrl::m_pstMain->m_stRoleConfigMgr.FindRoleAttrCfg(iID);
        CT_CHECK(iIndex, ERROR_ROLE_CAREER_ATTR_EMPTY_CFG);

        CRoleAttrCfgData& stAttrCfgData =
            CMainCtrl::m_pstMain->m_stRoleConfigMgr.GetRoleAttrCfg(iIndex);

        iBaseAttr = stAttr._aiAttr[iBaseType];

        stAttr._aiAttr[EXT_ATTR_HP] += iBaseAttr * stAttrCfgData.GetHP();

        stAttr._aiAttr[EXT_ATTR_PHY_ATK] +=
            iBaseAttr * stAttrCfgData.GetPhyAtk();

        stAttr._aiAttr[EXT_ATTR_PHY_DEF] +=
            iBaseAttr * stAttrCfgData.GetPhyDef();

        stAttr._aiAttr[EXT_ATTR_MAG_ATK] +=
            iBaseAttr * stAttrCfgData.GetMagAtk();

        stAttr._aiAttr[EXT_ATTR_MAG_DEF] +=
            iBaseAttr * stAttrCfgData.GetMagDef();

        stAttr._aiAttr[EXT_ATTR_HIT] += iBaseAttr * stAttrCfgData.GetHit();
        stAttr._aiAttr[EXT_ATTR_DODGE] += iBaseAttr * stAttrCfgData.GetDodge();

        stAttr._aiAttr[EXT_ATTR_DOUBLE] +=
            iBaseAttr * stAttrCfgData.GetDouble();

        stAttr._aiAttr[EXT_ATTR_ANTI_DOUBLE] +=
            iBaseAttr * stAttrCfgData.GetAntiDouble();

        stAttr._aiAttr[EXT_ATTR_BLOCK] += iBaseAttr * stAttrCfgData.GetBlock();

        stAttr._aiAttr[EXT_ATTR_ANTI_BLOCK] +=
            iBaseAttr * stAttrCfgData.GetAntiBlock();

        stAttr._aiAttr[EXT_ATTR_TURN_ORDRE] +=
            iBaseAttr * stAttrCfgData.GetOrder();

        stAttr._aiAttr[EXT_ATTR_CRIT] += iBaseAttr * stAttrCfgData.GetCrit();

        stAttr._aiAttr[EXT_ATTR_IMMUNE_INJURY] +=
            iBaseAttr * stAttrCfgData.GetImmuneInjury();

        stAttr._aiAttr[EXT_ATTR_REACT_INJURY] +=
            iBaseAttr * stAttrCfgData.GetReactInjury();

        stAttr._aiAttr[EXT_ATTR_PENETRATE] +=
            iBaseAttr * stAttrCfgData.GetPenetrate();

        stAttr._aiAttr[EXT_ATTR_TREATMENT] +=
            iBaseAttr * stAttrCfgData.GetTreatment();

        stAttr._aiAttr[EXT_ATTR_FIGHT_BACK] +=
            iBaseAttr * stAttrCfgData.GetFightBack();

        stAttr._aiAttr[EXT_ATTR_ACT_ANGER] +=
            iBaseAttr * stAttrCfgData.GetActAnger();
    }

    return 0;
}

//计算个体(主角或者伙伴)先手值的加成 主要是卡片等级
int CRoleMgr::AddObjTurnOrder(CPlayerAttr& stAttr, int iObjType,
        unsigned int uiObjID, CPlayerDetailInfo& stPlayerDetail,
        CPlayerOnlineData& stPlayerOnline)
{
    if (GAME_OBJ_TYPE_PLAYER != iObjType && GAME_OBJ_TYPE_PARTNER != iObjType)
    {
        CT_ERROR(("role(%u) add obj(%u) turn order obj type(%d) error!",
            stPlayerDetail._uiGID,uiObjID,iObjType));
        return ERROR_MATRIX_UNKNOWN_OBJ_TYPE;
    }

    int iRet = 0;
    int iIndex = 0;
    int iCardLevel = 0;
    int iEquipLevel = 0;
    if (GAME_OBJ_TYPE_PLAYER == iObjType)
    {
        iRet = CMainCtrl::m_pstMain->m_stCardMgr.GetTotalLevel(
            stPlayerOnline._stUserCard, stPlayerDetail._stPlayerWareCard,
            iCardLevel);
        CT_RETURN(iRet);
#if 0
        iEquipLevel = CMainCtrl::m_pstMain->m_stEquipMgr.GetStrengthTotalLevel(
            stPlayerOnline._stUserEquip, 0);
#endif
    }
    else if (GAME_OBJ_TYPE_PARTNER == iObjType)
    {
        iIndex = stPlayerDetail._stUserPartner.FindActData((short)uiObjID);
        CT_CHECK(iIndex, ERROR_PARTNER_NOT_IN_ACT);
        CPartnerActData& stActPartner =
            stPlayerDetail._stUserPartner.GetPartnerActData(iIndex);

        iRet = CMainCtrl::m_pstMain->m_stCardMgr.GetTotalLevel(
            stPlayerOnline._stUserCard, stActPartner._stPlayerWareCard,
            iCardLevel);
        CT_RETURN(iRet);
#if 0
        iEquipLevel = CMainCtrl::m_pstMain->m_stEquipMgr.GetStrengthTotalLevel(
            stPlayerOnline._stUserEquip, uiObjID);
#endif
    }

    stAttr._aiAttr[EXT_ATTR_TURN_ORDRE] += (iCardLevel + iEquipLevel);

    return 0;
}

void CRoleMgr::UpdateFightingInSns(CPlayerOnlineData & stPlayerOnline)
{
    unsigned uiGid = stPlayerOnline._uiGID;
    int iRoleFighting = GetRoleFighting(stPlayerOnline);
    int iTeamFighting = GetTeamFighting(stPlayerOnline);

    int iIndex = CMainCtrl::m_pstMain->m_stPlayerSnsCommInfoHash.HashFind(uiGid);
    if (iIndex < 0)
    {
        CT_ERROR(("%d, %d, %d", uiGid, iTeamFighting, iRoleFighting));
        return ;
    }

    CPlayerSnsCommInfo & stComm = CMainCtrl::m_pstMain->m_stPlayerSnsCommInfoHash[iIndex];
    if (iTeamFighting == stComm._iTeamFighting && iRoleFighting == stComm._iRoleFighting)
    {
        return ;
    }

    CCmdUpdateSnsDetail* pstCmd = (CCmdUpdateSnsDetail *)CT_CMDFACTORY->CreateCmd(ID_MAIN_INNER_UPDATE_SNS);
    if (pstCmd == NULL)
    {
        CT_ERROR(("%d, %d, %d", uiGid, iTeamFighting, iRoleFighting));
        return ;
    }

    pstCmd->_uiGid = uiGid;
    pstCmd->_ucType = CCmdUpdateSnsDetail::SNS_DETAIL_FIGHTING;
    pstCmd->_iTeamFighting = iTeamFighting;
    pstCmd->_iRoleFighting = iRoleFighting;
    pstCmd->Do(NULL);

    CT_TRACE(("UpdateFightingInSns: %d, %d, %d, %d", uiGid, iTeamFighting, iRoleFighting, CMainCtrl::m_pstMain->m_iNow));
    return ;
}

void CRoleMgr::DropTitle(unsigned int uiGID, EN_ROLE_TITLE_TYPE enTitle, int iExpiredTime)
{
    int iIndex = CMainCtrl::m_pstMain->m_stPlayerSnsCommInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("%d, %d, %d", uiGID, enTitle, iExpiredTime));
        return ;
    }

    //前台根据过期时间, 决定是否显示称号
    CCmdUpdateSnsDetail* pstCmd = (CCmdUpdateSnsDetail *)CT_CMDFACTORY->CreateCmd(ID_MAIN_INNER_UPDATE_SNS);
    if (pstCmd == NULL)
    {
        CT_ERROR(("%d, %d, %d", uiGID, enTitle, iExpiredTime));
        return ;
    }

    pstCmd->_uiGid = uiGID;
    pstCmd->_ucType = CCmdUpdateSnsDetail::SNS_DETAIL_TITLE;
    pstCmd->_stNewTitle._ucTitle = enTitle;
    pstCmd->_stNewTitle._iExpiredTime = iExpiredTime;
    pstCmd->Do(NULL);

    CMainCtrl::m_pstMain->m_stStatusMgr.NotifyUserStatusToMapByGID(uiGID);

    CT_TRACE(("DropTitle: %d, %d, %d, %d", uiGID, enTitle, CMainCtrl::m_pstMain->m_iNow, iExpiredTime));
    return;
}

int CRoleMgr::CheckRoleFreeze(CPlayerBaseInfo& stPlayerBase, int iFreezeType)
{
    switch (iFreezeType)
    {
    case ROLE_FREEZE_LOGIN: //冻结玩家登录
        {
            if (stPlayerBase._stFreezeData._iLoginLimit >
                CMainCtrl::m_pstMain->m_iNow)
            {
                return ERROR_FREEZE_ROLE_LOGIN;
            }
        }
        break;
    case ROLE_FREEZE_GOLD: //冻结玩家金币
        {
            if (stPlayerBase._stFreezeData._iGoldLimit >
                CMainCtrl::m_pstMain->m_iNow)
            {
                return ERROR_FREEZE_USE_GOLD;
            }
        }
        break;
    case ROLE_FREEZE_SILVER: //冻结玩家银币
        {
            if (stPlayerBase._stFreezeData._iSilverLimit >
                CMainCtrl::m_pstMain->m_iNow)
            {
                return ERROR_FREEZE_USE_SILVER;
            }
        }
        break;
    case ROLE_FREEZE_BAG: //冻结玩家背包
        {
            if (stPlayerBase._stFreezeData._iBagLimit >
                CMainCtrl::m_pstMain->m_iNow)
            {
                return ERROR_FREEZE_USE_BAG;
            }
        }
        break;
    case ROLE_FREEZE_STORGE: //冻结玩家仓库
        {
            if (stPlayerBase._stFreezeData._iStorgeLimit >
                CMainCtrl::m_pstMain->m_iNow)
            {
                return ERROR_FREEZE_USE_STORGE;
            }
        }
        break;
    case ROLE_FREEZE_SPEAK: //冻结玩家发言
        {
            if (stPlayerBase._stFreezeData._iSpeakLimit >
                CMainCtrl::m_pstMain->m_iNow)
            {
                return ERROR_FREEZE_ROLE_SPEAK;
            }
        }
        break;
    default:
        CT_WARNING(("check role(%u) unknown freeze type(%d)",
            stPlayerBase._uiGID,iFreezeType));
        break;
    }

    return 0;
}

void CRoleMgr::UpdateLoginDays (CPlayerDetailInfoEx1 & stDetail, int iNowTime)
{
    if (stDetail._iLoginDayCnt <= 0)
    {
        if (stDetail._iLoginDayCnt < 0)
        {
            CT_ERROR(("UpdateLoginDays %d, %d, %d, %d", stDetail._uiGID, stDetail._iLoginDayCnt, stDetail._iLastCalcDayTime, iNowTime));
        }

        stDetail._iLoginDayCnt = 1;
    }
    else
    {
        int iDays1 = CTTimeUtils::GetDaysOfSec(stDetail._iLastCalcDayTime);
        int iDays2 = CTTimeUtils::GetDaysOfSec(iNowTime);
        if (iDays1 == iDays2)
        {
            return ;
        }

        //是否跨了多天
        stDetail._iLoginDayCnt += CT_MAX((iDays2 - iDays1), 0);
    }

    CT_TRACE(("UpdateLoginDays %d, %d, %d, %d", stDetail._uiGID, stDetail._iLoginDayCnt, stDetail._iLastCalcDayTime, iNowTime));
    stDetail._iLastCalcDayTime = iNowTime;

    CVarObjectKey stKey;
    stKey.m_chDataType = DT_PLAYER_DETAIL_EX1_INFO;
    stKey.m_u64ID = stDetail._uiGID;
    CMainCtrl::m_pstMain->UpdateData(stKey, stDetail, VOP_UPDATE);
}

int CRoleMgr::GetTodayOnlineSeconds (CPlayerSnsDetailInfo& stSnsDetail, int iNowTime)
{
    int iThisOnlineTime = 0;

    if (CTTimeUtils::IsSameDay(iNowTime, stSnsDetail._stCommInfo._iLastLogInTime, 0))
    {
        //sns中的登录时间,是最原始的数据。
        iThisOnlineTime = (iNowTime - stSnsDetail._stCommInfo._iLastLogInTime);
    }
    else
    {
        //OSS中的登录时间, 在跨天的时候，做了修正.
        iThisOnlineTime = (iNowTime - stSnsDetail._stMyInfo._stPlayerOssInfo._iLastLoginTime);
    }

    return (iThisOnlineTime + stSnsDetail._stMyInfo._stPlayerOssInfo._iTodayLoginSec);
}

bool CRoleMgr::CheckRoleExist(unsigned int uiGID)
{
    int iIndex =  CMainCtrl::m_pstMain->m_stPlayerSnsCommInfoHash.HashFind(uiGID);
    if (iIndex >= 0)
    {
        return true;
    }

    return false;
}
